/*
 * Copyright (c) 2015 LingoChamp Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.liulishuo.magicprogresswidget;

import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Arc;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;

/**
 * Created by Jacksgong on 12/8/15.
 * <p/>
 * 轻量的ProgressBar
 */
public class MagicProgressBar extends Component implements Imag,
        Component.DrawTask, Component.EstimateSizeListener {
    private static final String MPB_PERCENT = "mpb_percent";
    private static final String MPB_FILL_COLOR = "mpb_fill_color";
    private static final String MPB_BACKGROUND_COLOR = "mpb_background_color";
    private static final String MPB_FLAT = "mpb_flat";

    private int cvsColor;
    private int backgroundColor;
    private Paint fillPaint;
    private Paint backgroundPaint;
    private float percentValue;
    private float magPercent;
    private boolean isFlat;
    private MagValueAnimator magValueAnimator;
    private long maxTime = ConstantUtil.MAX_TIME;

    private final RectFloat rectF = new RectFloat();
    private int width;
    private int height;
    private float radius;

    /**
     * MagicProgressBar
     *
     * @param context 上下文
     */
    public MagicProgressBar(Context context) {
        super(context);
        init(context, null);
    }

    /**
     * MagicProgressBar
     *
     * @param context 上下文
     * @param attrs   默认参数
     */
    public MagicProgressBar(Context context, AttrSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    /**
     * MagicProgressBar
     *
     * @param context   上下文
     * @param attrs     默认参数
     * @param styleName string数据
     */
    public MagicProgressBar(Context context, AttrSet attrs, String styleName) {
        super(context, attrs, styleName);
        init(context, attrs);
    }

    /**
     * MagicProgressBar
     *
     * @param context 上下文
     * @param attrs   默认参数
     * @param resId   int数据
     */
    public MagicProgressBar(Context context, AttrSet attrs, int resId) {
        super(context, attrs, resId);
        init(context, attrs);
    }

    private void init(final Context context, AttrSet attrs) {
        if (context == null || attrs == null) {
            return;
        }
        Util util = new Util(attrs);
        percentValue = util.getFloatValue(MPB_PERCENT, 0);
        cvsColor = util.getColorValue(MPB_FILL_COLOR, 0);
        backgroundColor = util.getColorValue(MPB_BACKGROUND_COLOR, 0);
        isFlat = util.getBooleanValue(MPB_FLAT, false);
        fillPaint = new Paint();
        fillPaint.setColor(new Color(cvsColor));
        fillPaint.setAntiAlias(true);
        backgroundPaint = new Paint();
        backgroundPaint.setColor(new Color(backgroundColor));
        backgroundPaint.setAntiAlias(true);
        addDrawTask(this);
        setEstimateSizeListener(this);
    }

    /**
     * 设置填充进度的颜色
     *
     * @param arColor 填充进度的颜色，argb
     */
    public void setFillColor(final int arColor) {
        if (this.cvsColor != arColor) {
            this.cvsColor = arColor;
            this.fillPaint.setColor(new Color(cvsColor));
            invalidate();
        }
    }

    /**
     * 进度背景的颜色
     *
     * @param bgColor 进度背景的颜色,argb
     */
    public void setBackgroundColor(final int bgColor) {
        if (this.backgroundColor != bgColor) {
            this.backgroundColor = bgColor;
            this.backgroundPaint.setColor(new Color(bgColor));
            invalidate();
        }
    }

    public int getFillColor() {
        return this.cvsColor;
    }

    public int getBackgroundColor() {
        return this.backgroundColor;
    }

    /**
     * ptInt
     *
     * @param percentInt fl值
     * @return percent
     */
    private float ptInt(float percentInt) {
        float pt = Math.max(0, percentInt);
        return pt;
    }

    @Override
    public float getPercent() {
        return this.percentValue;
    }

    @Override
    public void setPercent(float percent) {
        float pc = ptInt(percent);
        anim(0, pc, (long) (pc * maxTime));
    }

    @Override
    public void setPercent(float percent, long durationMillis) {
        float pc = ptInt(percent);
        anim(0, pc, durationMillis);
    }

    @Override
    public void setSmoothPercent(float percent) {
        float pc = ptInt(percent);
        anim(magPercent, pc, (long) ((pc - magPercent) * maxTime));
    }

    @Override
    public void setSmoothPercent(float percent, long durationMillis) {
        float pc = ptInt(percent);
        anim(magPercent, pc, durationMillis);
    }

    private void anim(float lastPercent, float percent, long duration) {
        if (magValueAnimator != null) {
            if (magValueAnimator.isRunning()) {
                magValueAnimator.end();
            }
            magValueAnimator.release();
        }
        magValueAnimator = MagValueAnimator.ofFloat(lastPercent, percent);
        magValueAnimator.setDuration(duration);
        magValueAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float value) {
                MagicProgressBar.this.percentValue = value;
                invalidate();
            }
        });
        magValueAnimator.start();
        this.magPercent = percent;
    }

    /**
     * 设置填充的进度条右侧是否是平面(不是平面就是圆弧)
     *
     * @param ft Whether the right side of progress is round or flat
     */
    public void setFlat(final boolean ft) {
        if (this.isFlat != ft) {
            this.isFlat = ft;
            invalidate();
        }
    }

    @Override
    public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
        width = EstimateSpec.getSize(widthEstimateConfig) - getPaddingLeft() - getPaddingRight();
        height = EstimateSpec.getSize(heightEstimateConfig) - getPaddingTop() - getPaddingBottom();
        radius = height / ConstantUtil.NUM_F_2;
        return false;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        float cvsWidth = percentValue * width;
        rectF.left = 0;
        rectF.top = 0;
        rectF.right = width;
        rectF.bottom = height;
        canvas.save();
        perWidth(canvas, cvsWidth);
    }

    private void perWidth(Canvas canvas, float cvsWidth) {
        if (backgroundColor != 0) {
            canvas.drawRoundRect(rectF, radius, radius, backgroundPaint);
        }
        try {
            if (cvsColor != 0 && cvsWidth > 0) {
                if (cvsWidth == width) {
                    rectF.right = cvsWidth;
                    canvas.drawRoundRect(rectF, radius, radius, fillPaint);
                    return;
                }
                if (isFlat) {
                    canvas.save();
                    rectF.right = cvsWidth > radius ? radius : cvsWidth;
                    canvas.clipRect(rectF);
                    rectF.right = radius * ConstantUtil.NUM_2;
                    canvas.drawRoundRect(rectF, radius, radius, fillPaint);
                    canvas.restore();
                    if (cvsWidth <= radius) {
                        return;
                    }
                    float leftAreaWidth = width - radius;
                    float centerX = cvsWidth > leftAreaWidth ? leftAreaWidth : cvsWidth;
                    rectF.left = radius;
                    rectF.right = centerX;
                    canvas.drawRect(rectF, fillPaint);
                    if (cvsWidth <= leftAreaWidth) {
                        return;
                    }
                    rectF.left = leftAreaWidth - radius;
                    rectF.right = cvsWidth;
                    canvas.clipRect(rectF);
                    rectF.right = width;
                    canvas.drawArc(rectF, new Arc(ConstantUtil.NUM_SUB_90, ConstantUtil.NUM_180, true), fillPaint);
                } else {
                    if (cvsWidth <= radius * ConstantUtil.NUM_2) {
                        rectF.right = cvsWidth;
                        canvas.clipRect(rectF);
                        rectF.right = radius * ConstantUtil.NUM_2;
                        canvas.drawRoundRect(rectF, radius, radius, fillPaint);
                    } else {
                        rectF.right = cvsWidth;
                        canvas.drawRoundRect(rectF, radius, radius, fillPaint);
                    }
                }
            }
        } finally {
            canvas.restore();
        }
    }
}
